#include "VulkanRenderPass.h"

namespace Alice
{
    VkRenderPass CreateVulkanRenderPass(VulkanDevice& InDevice, const VulkanRenderTargetLayout& RTLayout)
    {
        VkRenderPass OutRenderpass;
        VulkanRenderPassBuilder<FVulkanSubpassDescription<VkSubpassDescription>, FVulkanSubpassDependency<VkSubpassDependency>, VulkanAttachmentReference<VkAttachmentReference>, VulkanAttachmentDescription<VkAttachmentDescription>, FVulkanRenderPassCreateInfo<VkRenderPassCreateInfo>> Creator(InDevice);
        OutRenderpass = Creator.Create(RTLayout);
        return OutRenderpass;
    }
    VulkanRenderPass* VulkanRenderPassManager::GetOrCreateRenderPass(const VulkanRenderTargetLayout& inVulkanRenderTargetLayout)
    {
        auto iter=mRenderPasses.begin();
        auto iterEnd=mRenderPasses.end();
        while (iter!=iterEnd)
        {
            VulkanRenderPass*renderPass=*iter;
            if(renderPass->mLayout==inVulkanRenderTargetLayout)
            {
                return renderPass;
            }
            iter++;
        }
        VulkanRenderPass* renderPass = new VulkanRenderPass(*mDevice, inVulkanRenderTargetLayout);
        mRenderPasses.push_back(renderPass);
        return renderPass;
    }
    VulkanFramebuffer* VulkanRenderPassManager::GetOrCreateFramebuffer(const CGISetRenderTargetsInfo& inRenderTargetsInfo, const VulkanRenderTargetLayout& inVulkanRenderTargetLayout, VulkanRenderPass* inRenderPass)
    {
    	/*uint32 RTLayoutHash = inVulkanRenderTargetLayout.GetRenderPassCompatibleHash();

		uint64 MipsAndSlicesValues[MaxSimultaneousRenderTargets];
		for (int32 Index = 0; Index < MaxSimultaneousRenderTargets; ++Index)
		{
			MipsAndSlicesValues[Index] = ((uint64)inRenderTargetsInfo.ColorRenderTarget[Index].ArraySliceIndex << (uint64)32) | (uint64)inRenderTargetsInfo.ColorRenderTarget[Index].MipIndex;
		}
		RTLayoutHash = FCrc::MemCrc32(MipsAndSlicesValues, sizeof(MipsAndSlicesValues), RTLayoutHash);

		auto FindFramebufferInList = [&](FFramebufferList* InFramebufferList)
		{
			VulkanFramebuffer* OutFramebuffer = nullptr;

			for (int32 Index = 0; Index < InFramebufferList->Framebuffer.Num(); ++Index)
			{
				const VkRect2D RenderArea = InFramebufferList->Framebuffer[Index]->GetRenderArea();

				if (InFramebufferList->Framebuffer[Index]->Matches(inRenderTargetsInfo) &&
					((inVulkanRenderTargetLayout.GetExtent2D().width == RenderArea.extent.width) && (inVulkanRenderTargetLayout.GetExtent2D().height == RenderArea.extent.height) &&
						(inVulkanRenderTargetLayout.GetOffset2D().x == RenderArea.offset.x) && (inVulkanRenderTargetLayout.GetOffset2D().y == RenderArea.offset.y)))
				{
					OutFramebuffer = InFramebufferList->Framebuffer[Index];
					break;
				}
			}

			return OutFramebuffer;
		};

		FFramebufferList** FoundFramebufferList = nullptr;
		FFramebufferList* FramebufferList = nullptr;

		{
			FRWScopeLock ScopedReadLock(FramebuffersLock, SLT_ReadOnly);

			FoundFramebufferList = Framebuffers.Find(RTLayoutHash);
			if (FoundFramebufferList)
			{
				FramebufferList = *FoundFramebufferList;

				VulkanFramebuffer* ExistingFramebuffer = FindFramebufferInList(FramebufferList);
				if (ExistingFramebuffer)
				{
					return ExistingFramebuffer;
				}
			}
		}

		FRWScopeLock ScopedWriteLock(FramebuffersLock, SLT_Write);
		FoundFramebufferList = Framebuffers.Find(RTLayoutHash);
		if (!FoundFramebufferList)
		{
			FramebufferList = new FFramebufferList;
			Framebuffers.Add(RTLayoutHash, FramebufferList);
		}
		else
		{
			FramebufferList = *FoundFramebufferList;
			FVulkanFramebuffer* ExistingFramebuffer = FindFramebufferInList(FramebufferList);
			if (ExistingFramebuffer)
			{
				return ExistingFramebuffer;
			}
		}*/
		auto iter=mFrameBuffers.begin();
    	auto iterEnd=mFrameBuffers.end();
	    while (iter!=iterEnd)
	    {
		    VulkanFramebuffer*framebuffer=*iter;
	    	CGIVulkanTexture*colorAttachment0=reinterpret_cast<CGIVulkanTexture*>(inRenderTargetsInfo.ColorRenderTarget[0].Texture);
	    	if(colorAttachment0->mDefaultView->mTextureView.View==framebuffer->mColorAttachment0ImageView)
	    	{
	    		return framebuffer;
	    	}
	    	iter++;
	    }
		VulkanFramebuffer* framebuffer = new VulkanFramebuffer(*mDevice, inRenderTargetsInfo, inVulkanRenderTargetLayout, *inRenderPass);
    	mFrameBuffers.push_back(framebuffer);
		return framebuffer;
    }
}
